package com.rtsapp.naval.version.controller;

import com.rtsapp.naval.version.context.VersionContext;
import com.rtsapp.naval.version.model.RemoteFile;
import com.rtsapp.naval.version.model.RemotePlatform;
import com.rtsapp.naval.version.model.RemoteVersion;
import com.rtsapp.naval.version.model.ResultVersion;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping(value = "version")
public class VersionController {
    private static final Logger LOGGER = Logger.getLogger(VersionController.class);

    private static final int PLATFORM_IOS = 1;
    private static final int PLATFORM_ANDROID = 2;
    private static final int PLATFORM_ONESTORE = 3;


    @ResponseBody
    @RequestMapping(value = "getMaxVersion")
    public Object getMaxVersion() {


        VersionContext.refreshVersionContext();

        VersionContext versionContext = VersionContext.getInstanceInThread(false);
        Map<Integer, RemotePlatform> versionMap = versionContext.getVersionMap();

        int iosVersion = 0;
        int androidVersion = 0;
        int oneStoreVersion = 0;

        if (versionMap.get(PLATFORM_IOS) != null) {
            iosVersion = versionMap.get(PLATFORM_IOS).getMaxVersionNo();
        }

        if (versionMap.get(PLATFORM_ANDROID) != null) {
            androidVersion = versionMap.get(PLATFORM_ANDROID).getMaxVersionNo();
        }

        if (versionMap.get(PLATFORM_ONESTORE) != null) {
            oneStoreVersion = versionMap.get(PLATFORM_ONESTORE).getMaxVersionNo();
        }

        return iosVersion + "," + androidVersion + "," + oneStoreVersion;

    }


//    @ResponseBody
//    @RequestMapping(value = "getMaxVersion")
//    public Object getMaxVersion(  String p, String debug ) {
//
//
//        int clientPlatform;
//        boolean isDebug;
//
//        try {
//            clientPlatform = Integer.parseInt( p );
//            isDebug = Boolean.parseBoolean( debug);
//        } catch (Throwable e) {
//            return false;
//        }
//
//        VersionContext.refreshVersionContext();
//
//        VersionContext versionContext = VersionContext.getInstanceInThread(isDebug);
//        if( !versionContext.getVersionMap().containsKey( clientPlatform ) ){
//            return false;
//        }else {
//            Integer maxVersionNo = versionContext.getVersionMap().get(clientPlatform).getMaxVersionNo();
//            return maxVersionNo;
//        }
//    }


    @ResponseBody
    @RequestMapping(value = "getVersionInfo")
    public Object getVersionInfo(Model m, HttpServletRequest request, HttpServletResponse response, String p, String v, String c) {


        boolean isDebug = VersionContext.checkDebugUser(request.getRemoteHost());

        LOGGER.info("getVersionInfo, platform=" + p + ", version=" + v + ", channel=" + c + ", isDebug" + isDebug);

        int clientPlatform;
        int clientVersion;
        String clientChannel;
        try {
            clientPlatform = Integer.parseInt(p);
            clientVersion = Integer.parseInt(v);
            clientChannel = c == null ? "DEFAULT" : c.toUpperCase();
        } catch (Throwable e) {
            Map<String, String> errInfo = new HashMap<>();
            errInfo.put("err", "parameter error");
            return errInfo;
        }
        VersionContext.refreshVersionContext();

        VersionContext versionContext = VersionContext.getInstanceInThread(isDebug);

        RemoteVersion tmpRemoteVersion = versionContext.getAppVersion(clientPlatform, clientVersion);
        String channel = null;
        if (tmpRemoteVersion.getChannelDownloadSite() != null) {
            channel = tmpRemoteVersion.getChannelDownloadSite().get(clientChannel);
            if (channel == null) {
                channel = tmpRemoteVersion.getChannelDownloadSite().get("DEFAULT");
            }
        }

        RemoteVersion remoteVersion = new RemoteVersion(tmpRemoteVersion.getPlatform(),
                tmpRemoteVersion.getVersionNo(),
                tmpRemoteVersion.isMilestone(),
                channel,
                null,
                tmpRemoteVersion.getMd5(),
                tmpRemoteVersion.getSize(),
                tmpRemoteVersion.getFilesUrlPrefix(),
                tmpRemoteVersion.getFiles());

        return new ResultVersion(remoteVersion);
    }

    @ResponseBody
    @RequestMapping(value = "admin/genVersion")
    public Object genVersion(Model m, HttpServletRequest request, String u, String p, String version) {
        /***
         * isDebug
         * platform
         * pkgVersion{
         *     versionNo
         *     downloadSite
         * }
         * maxVersionNo
         * urlPrefix
         * versions[
         *  {
         *      versionNo
         *      partSize
         *      md5
         *      size
         *  }
         * ]
         */
        Map<String, String> res = new HashMap<>();

        boolean superUser = false;
        if (!checkUser(u, p)) {
            res.put("res", "Identity is incorrect");
            return res;
        }
        if (u.equals("superadmin")) {
            superUser = true;
        }

        version = version.replace("^-^", "&");

        LOGGER.info("genVersion, userName=" + u + ", versionInfo=" + version);

        JSONObject json = new JSONObject(version);
        int platform = json.getInt("platform");
        if (!json.getBoolean("isDebug")) {
            if (!superUser) {
                res.put("res", "error");
                res.put("msg", "Permission denied");
                return res;
            }
            VersionContext.genInstance(false, platform, null);
            VersionContext.saveVersionInfo();
            res.put("res", "success");
            return res;
        }
        String platformName;
        switch (platform) {
            case PLATFORM_IOS:
                platformName = "IOS";
                break;
            case PLATFORM_ANDROID:
                platformName = "Android";
                break;
            case PLATFORM_ONESTORE:
                platformName = "OneStore";
                break;
            default:
                platformName = "";
                break;
        }
        JSONObject pkgVersionJson = json.getJSONObject("pkgVersion");

        Map<String, String> channelDownloadSite = new HashMap<>();
        if (pkgVersionJson.has("channelDownloadSites")) {
            JSONObject channelDownloadSitesJson = pkgVersionJson.getJSONObject("channelDownloadSites");

            if (channelDownloadSitesJson != null) {
                for (String key : channelDownloadSitesJson.keySet()) {
                    channelDownloadSite.put(key, channelDownloadSitesJson.getString(key));
                }
            }
        }

        int partLength = 512;
        if (json.has("partLength")) {
            partLength = json.getInt("partLength");
        }

        RemoteVersion pkgVersion = new RemoteVersion(platform, pkgVersionJson.getInt("versionNo"), true, pkgVersionJson.getString("downloadSite"), channelDownloadSite, null, 0, null, null);

        int maxVersionNo = json.getInt("maxVersionNo");
        String urlPrefix = json.getString("urlPrefix");

        JSONArray versions = json.getJSONArray("versions");
        Map<Integer, RemoteVersion> appVersionMap = new HashMap<>();
        for (Object versionObj : versions) {
            JSONObject versionJson = (JSONObject) versionObj;

            int versionNo = versionJson.getInt("versionNo");

            List<RemoteFile> files = new ArrayList<>();
            int partSize = versionJson.getInt("partSize");
            JSONArray fileJsons = versionJson.getJSONArray("files");
            for (int i = 0; i < partSize; i++) {
                int size = 0;
                if (i < partSize - 1) {
                    size = partLength * 1024;
                } else {
                    size = versionJson.getInt("size") - (partLength * 1024) * (partSize - 1);
                }
                String md5 = "";
                if (fileJsons != null) {
                    md5 = fileJsons.getJSONObject(i).getString("md5");
                }
                files.add(new RemoteFile(md5, size, "upload_" + maxVersionNo + "_" + versionNo + ".zip." + String.format("%0" + String.valueOf(partSize - 1).length() + "d", i) + ".part"));
            }
            RemoteVersion remoteVersion = new RemoteVersion(platform, maxVersionNo, false, null, null, versionJson.getString("md5"), versionJson.getInt("size"), urlPrefix.replace("${platform}", platformName).replace("${versionNo}", "" + versionNo).replace("${maxVersionNo}", "" + maxVersionNo), files);
            appVersionMap.put(versionNo, remoteVersion);
        }

        RemoteVersion remoteVersion = new RemoteVersion(platform, maxVersionNo, false, null, null, null, 0, null, null);
        appVersionMap.put(maxVersionNo, remoteVersion);

        RemotePlatform remotePlatformObj = new RemotePlatform(pkgVersion.getVersionNo(), maxVersionNo, appVersionMap, pkgVersion);

        if (VersionContext.genInstance(true, platform, remotePlatformObj)) {
            VersionContext.saveVersionInfo();
            res.put("res", "success");
            return res;
        }
        res.put("res", "error");
        res.put("msg", "current versionNo < or = max versionNo");
        return res;
    }

    @ResponseBody
    @RequestMapping(value = "admin/superUserHost")
    public Object superUserHost(Model m, HttpServletRequest request, String u, String p, String t, String h) {

        Map<String, String> res = new HashMap<>();
        if (!checkUser(u, p)) {
            res.put("res", "Identity is incorrect");
            return res;
        }

        switch (t) {
            case "add":
                if (h.trim().length() > 0) {
                    VersionContext.getDebugHosts().add(h.trim());
                }
                break;
            case "del":
                if (h.trim().length() > 0) {
                    VersionContext.getDebugHosts().remove(h.trim());
                }
                break;
            case "clr":
                VersionContext.getDebugHosts().clear();
                break;
        }

        return VersionContext.getDebugHosts();
    }

    @ResponseBody
    @RequestMapping(value = "admin/getAllVersionInfo")
    public Object getAllVersionInfo(Model m, HttpServletRequest request, String u, String p) {

        Map<String, String> res = new HashMap<>();
        if (!checkUser(u, p)) {
            res.put("err", "parameter error");
            return res;
        }

        return VersionContext.getAllVersion();
    }

    private boolean checkUser(String userName, String password) {
        try {
            SAXReader saxReader = new SAXReader();
            Document dom = saxReader.read(new File("cfg/user.xml"));
            Element root = dom.getRootElement();
            Element user = root.element(userName);

            if (user != null) {
                String pwd = user.attributeValue("pwd");
                if (pwd != null && pwd.equals(password)) {
                    return true;
                }
            }

        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return false;
    }

    private boolean checkSuperUser(String userName, String password) {
        if (checkUser(userName, password) && userName.equals("superadmin")) {
            return true;
        }
        return false;
    }


    @ResponseBody
    @RequestMapping(value = "admin/replaceHost")
    public Object replaceHost(Model m, HttpServletRequest request, String oldUrl, String newUrl, String u, String pw, boolean debug, int p) {

        LOGGER.info("replaceHost, oldUrl=" + oldUrl + ", newUrl=" + newUrl + ", userName=" + u + ", isDebug=" + debug + ", platform=" + p);

        Map<String, String> res = new HashMap<>();
        if (!checkSuperUser(u, pw)) {
            res.put("err", "parameter error");
            return res;
        }

        Map<Integer, RemoteVersion> versions = VersionContext.getAllVersion().get(debug ? "debugVersion" : "releaseVersion").get(p).getVersionMap();
        for (RemoteVersion version : versions.values()) {
            if (version.isMilestone()) {
                continue;
            }
            version.setFilesUrlPrefix(version.getFilesUrlPrefix().replace(oldUrl, newUrl));
        }
        return VersionContext.getAllVersion();
    }


}
